package org.origin.ferret.system.service.impl;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.origin.centre.model.base.XPage;
import org.origin.centre.model.consts.XConst;
import org.origin.centre.model.dto.XDeleteByIdDto;
import org.origin.centre.model.dto.XQueryByIdDto;
import org.origin.centre.model.dto.XUpdateByIdDto;
import org.origin.centre.model.vo.XPageVo;
import org.origin.centre.utils.UserUtil;
import org.origin.ferret.system.mapper.SysUserMapper;
import org.origin.ferret.system.mapstruct.SysUserMapstruct;
import org.origin.ferret.system.model.dto.user.SysUserInsertDto;
import org.origin.ferret.system.model.dto.user.SysUserPageDto;
import org.origin.ferret.system.model.dto.user.SysUserPasswordDto;
import org.origin.ferret.system.model.dto.user.SysUserUpdateDto;
import org.origin.ferret.system.model.entity.SysUserEntity;
import org.origin.ferret.system.model.enums.UserStatusEnum;
import org.origin.ferret.system.model.vo.user.SysUserVo;
import org.origin.ferret.system.service.SysUserService;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Objects;

import static org.origin.ferret.system.model.entity.table.SysUserEntityTableDef.SYS_USER_ENTITY;

/**
 * 系统用户-服务实现
 *
 * @author ferret
 * @version 2024-05-08
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl implements SysUserService {
    private final SysUserMapper userMapper;
    private final SysUserMapstruct userMapstruct;
    private final PasswordEncoder passwordEncoder;

    @Override
    public XPageVo<SysUserVo> page(XPage<SysUserPageDto> pageDto) {
        SysUserPageDto params = pageDto.getParams();
        Page<SysUserEntity> pagePojo = this.userMapper
                .paginate(pageDto.getPageNum(), pageDto.getPageSize(), QueryWrapper.create()
                        .where(SYS_USER_ENTITY.ID.gt(1, !UserUtil.isAdmin())) // 默认过滤掉超级管理员，只有超级管理员才能查看到超级管理员账号
                        .and(SYS_USER_ENTITY.NAME.like(params.getName(), StringUtils::isNotBlank))
                        .and(SYS_USER_ENTITY.PHONE.like(params.getPhone(), StringUtils::isNotBlank))
                        .and(SYS_USER_ENTITY.IDENTITY.eq(params.getIdentity(), StringUtils::isNotBlank))
                        .and(SYS_USER_ENTITY.ACCOUNT.eq(params.getAccount(), StringUtils::isNotBlank))
                        .and(SYS_USER_ENTITY.GENDER.eq(params.getGender(), StringUtils::isNotBlank))
                        .and(SYS_USER_ENTITY.STATUS.eq(params.getStatus(), Objects::nonNull))
                        .orderBy(SYS_USER_ENTITY.STATUS.asc())
                        .orderBy(SYS_USER_ENTITY.CREATE_TIME.desc())
                        .orderBy(SYS_USER_ENTITY.ID.desc())
                );
        return new XPageVo<SysUserVo>()
                .of(pageDto, pagePojo.getTotalRow(),
                        pagePojo.getRecords(), this.userMapstruct::toVo);
    }

    @Override
    public SysUserVo query(XQueryByIdDto queryDto) {
        if (XConst.ADMIN_ID.equals(queryDto.getId()) && !UserUtil.isAdmin()) return null;
        SysUserEntity entity = this.userMapper.selectOneById(queryDto.getId());
        return this.userMapstruct.toVo(entity);
    }

    @Override
    public Boolean insert(SysUserInsertDto insertDto) {
        try {
            SysUserEntity entity = this.userMapstruct.toEntity(insertDto);
            entity.setStatus(UserStatusEnum.NORMAL.getCode());
            entity.setPassword(this.passwordEncoder.encode(insertDto.getPassword()));
            entity.preInsert();
            int insertNum = this.userMapper.insert(entity);
            return insertNum > 0;
        } catch (DuplicateKeyException e) {
            throw new IllegalArgumentException("[" + insertDto.getAccount() + "]账号已存在！");
        }
    }

    @Override
    public Boolean update(SysUserUpdateDto updateDto) {
        Assert.isTrue(this.hasAuthority(updateDto.getId()), "您没有权限修改超级管理员账号");
        SysUserEntity entity = this.userMapstruct.toEntity(updateDto);
        entity.setAccount(null);
        entity.setPassword(null);
        entity.setStatus(null);
        entity.preUpdate();
        int updateNum = this.userMapper.update(entity);
        return updateNum > 0;
    }

    @Override
    public Boolean delete(XDeleteByIdDto deleteDto) {
        Assert.isTrue(!XConst.ADMIN_ID.equals(deleteDto.getId()), "不能删除超级管理员账号");
        int updateNum = this.userMapper.deleteById(deleteDto.longId());
        return updateNum > 0;
    }

    @Override
    public Boolean valid(XUpdateByIdDto updateDto) {
        SysUserEntity entity = new SysUserEntity();
        entity.setId(updateDto.longId());
        entity.setStatus(UserStatusEnum.NORMAL.getCode());
        entity.preUpdate();
        int updateNum = this.userMapper.update(entity);
        return updateNum > 0;
    }

    @Override
    public Boolean invalid(XUpdateByIdDto updateDto) {
        SysUserEntity entity = new SysUserEntity();
        entity.setId(updateDto.longId());
        entity.setStatus(UserStatusEnum.FREEZE.getCode());
        entity.preUpdate();
        int updateNum = this.userMapper.update(entity);
        return updateNum > 0;
    }

    @Override
    public Boolean password(SysUserPasswordDto passwordDto) {
        Assert.isTrue(this.hasAuthority(passwordDto.getId()), "您没有权限重置超级管理员账号密码");
        SysUserEntity userEntity = this.userMapper.selectOneById(passwordDto.getId());
        Assert.notNull(userEntity, "未知的用户信息！");
        if (!this.passwordEncoder.matches(passwordDto.getOldPassword(), userEntity.getPassword())) {
            throw new IllegalArgumentException("用户旧密码错误！");
        }
        SysUserEntity entity = new SysUserEntity();
        entity.setId(passwordDto.getId());
        entity.setPassword(this.passwordEncoder.encode(passwordDto.getNewPassword()));
        entity.preUpdate();
        int updateNum = this.userMapper.update(entity);
        return updateNum > 0;
    }

    /**
     * 检查当前用户是否有权限。
     *
     * @param id 与权限相关联的ID。对于不同的使用场景，这个ID的含义可能不同（例如，它可能代表一个资源的ID，或者是一个用户的ID）。
     * @return 返回一个布尔值。如果当前用户有权限，则返回true；如果当前用户没有权限，则返回false。
     */
    private boolean hasAuthority(Object id) {
        // 首先检查当前用户是否是管理员，如果是，则直接返回true，拥有所有权限
        if (UserUtil.isAdmin()) {
            return true;
        }
        // 检查传入的ID是否不为空，并且不是管理员专用的ID
        return id != null && !XConst.ADMIN_ID.equals(id.toString());
    }
}
